#pragma once
/*
 * pipe module for servers. 
 */
#include <map>
#include <functional>
#include "singleton.h"
#include "pipe.h"
#include "rpc/rpc_stream.hpp"
#include "rpc/rpc_handle.hpp"
#include "log.h"

// server's handler interface.
class CServer;
class IServerHandler {
public:
	virtual ~IServerHandler() {}

	// message handler callback.
	virtual void Handle(const char* msg, int len, CServer* pServer) = 0;

	// status handler callback.
	virtual void OnStatus(bool isConnect, CServer* pServer) = 0;
};

// CServer is server template(with message and status function callback) to implement anet::pipe::IPipeMsgHandler.
class CServer : public anet::pipe::IPipeMsgHandler {
public:
	CServer(IServerHandler *iHandler) : m_pipe(nullptr), m_iHandler(iHandler)  {
	}
	virtual ~CServer() {
		m_iHandler = nullptr;
	}

public:
	void SetPipe(anet::pipe::IPipe* pipe) {
		m_pipe = pipe;
	}
	anet::pipe::IPipe* GetPipe() {
		return m_pipe; 
	}

	// send message(or with message id);
	bool Send(const char* msg, int len);
	bool Send(unsigned short msgId, const char* msg, int len);

	// remote_call calls remote server function where method is function name, and args are function's parameter.
	template <typename ... Args>
	bool remote_call(const std::string& method, Args&& ...args) {
		m_stream.reset();
		try {
			anet::rpc_codec::pack_remote_call(m_stream, method, std::forward<Args>(args)...);
			return this->Send(m_stream.c_str(), m_stream.size());
		} catch (const std::invalid_argument& e) {
			LogACrit("remote_call %s error:%s",method.c_str(), e.what());
			return false;
		}
	}

public:
	// interface to implement anet::pipe::IPipeMsgHandler.
	virtual void Handle(const char* msg, int len);
	void onStatus(bool isConnect);

private:
	// RPC stream.
	anet::rpc_codec::rpc_stream m_stream;

	// Pipe module.
	anet::pipe::IPipe* m_pipe;

	// Message handler.
	IServerHandler* m_iHandler;
};

// CServerMgr is a server manager to implement anet::pipe::IPipeReporter
class CServerMgr final : public anet::pipe::IPipeReporter {
	DECLARE_SINGLETON(CServerMgr);
protected:
	CServerMgr();
	virtual ~CServerMgr();

public:
	// pipe status callback.
	virtual void OnReport(bool isConnected, anet::pipe::IPipe* pipe);

public:
	// find TYPE Server.
	CServer* findType(int TYPE);

	// find a db server.
	CServer* findDBServer();

	// find a game server.
	CServer* findGameServer();

	// find server with id.
	CServer* findDBServerWithId(unsigned int id);
	CServer* findGameServerWithId(unsigned int id);

protected:
	CServer* createServer(anet::pipe::IPipe* pipe);

private:
	std::map<unsigned int, CServer*> m_servers;
};

// CPipeModule is pipe module.
class CPipeLog;
class CPipeModule final {
	DECLARE_SINGLETON(CPipeModule);
protected:
	CPipeModule();
	virtual ~CPipeModule();

public:
	// initialize pipe module.
	bool Init(const char* pipeFilePath, anet::pipe::IPipeReporter* reporter);

	// Run pipe events.
	bool Run(int count);

private:
	CPipeLog* m_log;
	anet::pipe::IPipeModule* m_pipeModule;
};